<?php

declare(strict_types=1);

namespace App\User\Service;

use App\Common\Constants\ErrorCode;
use App\Common\Service\BaseService;
use App\Resource\Model\ShopGroupModel;
use App\Resource\Model\ShopModel;
use App\User\Event\UserDeleted;
use App\User\Event\UserLogin;
use App\User\Model\MemberModel;
use App\User\Model\ModelHasRolesModel;
use App\User\Model\UserModel;
use App\User\Model\UserShopModel;
use Exception;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Context;
use Psr\SimpleCache\InvalidArgumentException;

class UserService extends BaseService
{

    /**
     * @param int $id
     * @param int $type  type = 1,后台管理员账号，type = 2，门店账号
     *
     * @return array
     */
    public function getInfoById(int $id, int $type = 1)
    {
        if ($type == 1) {
            // 后台管理员
            $data = UserModel::query()->where('id', $id)->where('role', '<>', 3)->first();
            $roleIdArr = ModelHasRolesModel::query()->where(['model_id' => $data['id']])->pluck('role_id')->toArray();
            if (count($roleIdArr) > 0) {
                $roleId = implode(',', $roleIdArr);
                $data['role_id'] = $roleId;
            } else {
                $data['role_id'] = '';
            }
            return ['code' => ErrorCode::SUCCESS, 'data' => $data];
        } else {
            // 门店账号
            $data = UserModel::query()->where('id', $id)->where('role', 3)->select('id', 'username', 'phone', 'last_login_at', 'status', 'created_at')->first();
            if (!$data) {
                return ['code' => ErrorCode::NOT_EXIST];
            }
            $data = $data->toArray();
            $shop_id = UserShopModel::where(['uid' => $data['id']])->value('shop_id');
            if ($shop_id) {
                $shop_info = ShopModel::where(['shop_id' => $shop_id])->select('shop_id', 'shop_group_id', 'shop_name', 'address as shop_address', 'create_at as shop_create_at', 'status as shop_status')->get()->toArray();
                foreach ($shop_info as $key => $val) {
                    $shop_info[$key]['shop_group_name'] = $this->getGroupNameById($val['shop_group_id']);
                }
                $shop_info = array_values($shop_info);
                $data['shop_id'] = $shop_id;
                $data['shop_info'] = $shop_info;
            } else {
                $data['shop_id'] = null;
                $data['shop_info'] = null;
            }
            return ['code' => ErrorCode::SUCCESS, 'data' => $data];
        }
    }

    /**
     * @param int $shop_group_id
     *
     * @return mixed
     */
    public function getGroupNameById(int $shop_group_id)
    {
        return ShopGroupModel::where(['id' => $shop_group_id])->value('shop_group_name');
    }

    /**
     * @param array $where
     * @param int $perPage
     * @param array|string[] $field
     * @param int $type 1后台管理员，2门店账号操作
     *
     * @return array
     */
    public function getList(array $where, int $perPage = 15, array $field = ['*'], int $type = 1)
    {
        $query = UserModel::query();
        !empty($where['username']) && $query->whereRaw('INSTR(username, ?) > 0', [$where['username']]);
        !empty($where['phone']) && $query->whereRaw('INSTR(phone, ?) > 0', [$where['phone']]);
        if (array_key_exists('status',$where) && in_array($where['status'],['0','1'])) {
            $query->where('status', '=', $where['status']);
        }
        if ($type == 2) {
            //通过门店名称搜索
            if (!empty($where['shop_name'])) {
                $shop_id = ShopModel::query()->where('shop_name','like', '%'.trim($where['shop_name']).'%')->pluck('shop_id')->toArray();
                $uid = UserShopModel::whereIn('shop_id', $shop_id)->pluck('uid') -> toArray();
//                var_dump($uid);die;
//                $query->where('id', '=', $uid);
                $query->whereIn('id', $uid);
            }
            //通过店群 id 搜索
            if (!empty($where['shop_group_id'])) {
                $shop_ids = ShopModel::where('shop_group_id', $where['shop_group_id'])->pluck('shop_id')->toArray();
                $uids = UserShopModel::whereIn('shop_id', $shop_ids)->pluck('uid')->toArray();
                $query->whereIn('id', $uids);
            }
            $query->where('role', '=', 3);
        } else {
            $query->where('role', '<>', 3);
        }

        $list = $query->orderBy('id','desc')->paginate($perPage, $field);

//        var_dump($list);die;

        if ($type == 2) {
            // TODO 本写法可以适用于一个门店账号下绑定多家店铺，如果只是一对一关系，后期可优化
            foreach ($list as $key => $val) {
                $shop_ids = UserShopModel::where(['uid' => $val['id']])
                    ->pluck('shop_id')->all();
                $shop_list = ShopModel::whereIn('shop_id', $shop_ids)
                    ->pluck('shop_name')->toArray();
                $list[$key]['shop_name'] = $shop_list;
            }
        } else {
            //获取用户的角色名称
            foreach ($list as $key => $val) {
                $roleName = $val->getRoleNames()->toArray();
                if (count($roleName) > 0) {
                    $roleNameStr = implode(',', $roleName);
                } else {
                    $roleNameStr = '';
                }
                $list[$key]['role_name'] = $roleNameStr;
            }
        }
        return ['code' => ErrorCode::SUCCESS, 'data' => $list];

    }

    /**
     * @param int $perPage
     *
     * @return mixed
     */
    public function getDestoryList(int $perPage)
    {
        $data = UserModel::onlyTrashed()->paginate($perPage);
//        $shop_info = StoreShopModel::all(['shop_id', 'shop_name'])->toArray();
//        $shop_list = array_column($shop_info, 'shop_name', 'shop_id');
//        foreach ($data as $key => $val) {
//            $data[$key]['shop_name'] = array_key_exists($val['shop_id'], $shop_list) ? $shop_list[$val['shop_id']] : null;
//        }

        return ['code' => ErrorCode::SUCCESS, 'data' => $data];
    }

    /**
     * @param array $params
     * @param int $type 2管理员，3门店账号
     *
     * @return array
     */
    public function add(array $params, int $type = 3)
    {
        //验证手机号
        $phone = $params['phone'];
        $phoneExist = UserModel::query()->where(['role' => $type,'phone' => $phone])->exists();
        if($phoneExist){
            return ['code' => ErrorCode::PHONE_EXIST];
        }

        if ($type == 2) {
            // 添加管理员
            try {
                DB::transaction(function () use ($params, $type) {
                    $res = UserModel::create([
                        'username' => $params['username'],
                        'password' => password_hash($params['password'], PASSWORD_DEFAULT),
                        'phone' => $params['phone'],
                        'role' => $type
                    ]);
                    //为管理员分配角色
                    if ($params['role_id']) {
                        $addRole = $this->syncRoleToUser($res, $params['role_id']);
                        if ($addRole['code']) {
                            throw new \Exception('角色分配失败', ErrorCode::ADD_ROLE_FAILE);
                        }
                    }
                    Context::set('uid', $res -> id);
                });
            } catch (Exception $e) {
                if ($e->getCode() == ErrorCode::ADD_ROLE_FAILE) {
                    return ['code' => ErrorCode::ADD_ROLE_FAILE];
                } else {
                    return ['code' => ErrorCode::NOT_IN_FORCE];
                }
            }
            $this->updateRedisAdminUser();
            $uid = Context::get('uid');
            return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $uid]];
        } else {
            // 添加门店账号
            try {
                DB::transaction(function () use ($params, $type) {
                    $res = UserModel::create([
                        'username' => $params['username'],
                        'phone' => $params['phone'],
                        'password' => password_hash($params['password'],
                            PASSWORD_DEFAULT),
                        'role' => $type,
                    ]);
                    $uid = $res->id;
                    $shop_id = $params['shop_id'];
                    $res = $this->bindUidWithShop((int)$uid, (int)$shop_id);
                    if ($res['code']) {
                        throw new \Exception('绑定门店失败', ErrorCode::FORBID_BIND);
                    }
                    Context::set('uid', $uid);
                });
            } catch (Exception $e) {
                if ($e->getCode() == ErrorCode::FORBID_BIND) {
                    return ['code' => ErrorCode::FORBID_BIND];
                } else {
                    return ['code' => ErrorCode::NOT_IN_FORCE];
                }
            }
            $uid = Context::get('uid');
            return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $uid]];
        }
    }

    /**
     * @param array $params
     *
     * @return array
     */
    public function update(array $params)
    {

        $user = UserModel::query()->find($params['id']);
        if (!$user) {
            return ['code' => ErrorCode::NOT_EXIST];
        }

        //验证手机号
        $phone = $params['phone'];
        $phoneExist = UserModel::query()->where(['role' => $user->role,'phone' => $phone])->whereNotIn('id', [$params['id']])->exists();
        if($phoneExist){
            return ['code' => ErrorCode::PHONE_EXIST];
        }
        $attributes = [
            'password' => array_key_exists('password', $params) ? password_hash($params['password'], PASSWORD_DEFAULT) : $user->password,
            'phone' => $params['phone'] ? $params['phone'] : $user->phone
        ];
        try {
            DB::transaction(function () use ($user, $attributes, $params) {
                $user->update($attributes);
                //店铺账号绑定店铺
                if (array_key_exists('shop_id', $params)) {
                    $shop = ShopModel::query()->where(['shop_id' => $params['shop_id']])->exists();
                    if (!$shop) {
                        throw new \Exception('所选店铺不存在', ErrorCode::NOT_EXIST);
                    }
                    $res = $this->bindUidWithShop((int)$params['id'], (int)$params['shop_id'], true);
                    if ($res['code']) {
                        throw new \Exception('绑定门店失败', ErrorCode::BIND_SHOP_FAILE);
                    }
                }

                //为管理员分配角色
                if (array_key_exists('role_id', $params)) {
                    $addRole = $this->syncRoleToUser($user, $params['role_id']);
                    if ($addRole['code']) {
                        throw new \Exception('分配角色失败', ErrorCode::ADD_ROLE_FAILE);
                    }
                }
            });
        } catch (Exception $e) {
            if ($e->getCode() == ErrorCode::NOT_EXIST) {
                return ['code' => ErrorCode::NOT_EXIST];
            } elseif ($e->getCode() == ErrorCode::BIND_SHOP_FAILE) {
                return ['code' => ErrorCode::BIND_SHOP_FAILE];
            } elseif ($e->getCode() == ErrorCode::ADD_ROLE_FAILE) {
                return ['code' => ErrorCode::ADD_ROLE_FAILE];
            }
            return ['code' => ErrorCode::FORBID_BIND];
        }
        $this->updateRedisAdminUser();
        return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $params['id']]];
    }

    /**
     * @param object $userModel
     * @param string $roleId
     *
     * @return array
     */
    public function syncRoleToUser(object $userModel, string $roleId)
    {
        $roleArr = explode(',', $roleId);
        for ($i = 0; $i < count($roleArr); $i++) {
            $arr[$i] = intval($roleArr[$i]);
        }
        try {
            $userModel->syncRoles($arr);
        } catch (Exception $e) {
            return ['code' => ErrorCode::NOT_IN_FORCE];
        }
        return ['code' => ErrorCode::SUCCESS];
    }

    /**
     * @param int $id
     *
     * @return array
     */
    public function delete(int $id)
    {
        $res = UserModel::where('id', $id)->delete();
        if ($res) {
            $this->eventDispatcher->dispatch(new UserDeleted($id));
            $this->updateRedisAdminUser();
            return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $id]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }

    /**
     * @param int $id
     *
     * @return array
     */
    public function forceDelete(int $id)
    {
        $res = UserModel::where('id', $id)->forceDelete();

        if ($res) {
            $this->eventDispatcher->dispatch(new UserDeleted($id));
            return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $id]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }

    /**
     * @param string $ids
     *
     * @return array
     */
    public function restore(string $ids)
    {
        $idsArr = explode(',', $ids);
        $res = UserModel::whereIn('id', $idsArr)->restore();

        if ($res) {
            return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['remarks' => '恢复ID：'.$ids]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }

    /**
     * @param int $uid
     *
     * @return mixed
     */
    public static function getUsernameByUid(int $uid)
    {
        return UserModel::where(['id' => $uid])->value('username');
    }

    /**
     * @param string $username
     * @param string $password
     *
     * @return array
     * @throws InvalidArgumentException
     */
    public function login(string $username, string $password)
    {
        //验证用户账户密码
        $where[] = ['username', '=', $username];
        $where[] = ['role', '<>', 3];
        $user = UserModel::query()->where($where)->first();
        if ($user) {
            if (password_verify($password, $user->password)) {
                $userData = [
                    'uid' => $user->id,
                    'username' => $user->username,
                ];
                $token = $this->jwt->setScene('default')->getToken($userData);
                $data = [
                    'token' => (string)$token,
                    'scene' => $this->jwt->getScene(),
                    'exp' => $this->jwt->setScene('default')->getTTL(),
                ];
                $this->eventDispatcher->dispatch(new UserLogin($user,$data));
//                $this->eventDispatcher->dispatch(new UserLogin($user));
//                $this->userRedis->set($user->username, $token, 7200);

                return ['code' => ErrorCode::SUCCESS, 'data' => $data];
            } else {
                return ['code' => ErrorCode::AUTH_ERROR];
            }
        } else {
            return ['code' => ErrorCode::AUTH_ERROR];
        }
    }


    /**
     * @return bool
     * @throws InvalidArgumentException
     */
    public function logout()
    {
        if ($this->jwt->logout()) {
            return true;
        }
        return false;
    }

    /**
     * @param int $uid
     * @param int $shop_id
     * @param bool $type 为 true 修改，为 false 新增
     *
     * @return array
     */
    public function bindUidWithShop(int $uid, int $shop_id, bool $type = false)
    {
        if ($type) {
            // 店铺账号修改绑定店铺，只需要检查要绑定的店铺是否已被绑定,（目前，该步骤已在验证器验证）
//            $is_exist = UserShopModel::where('shop_id', $shop_id)->first();
            $is_exist = false;
        }
//        else {
//            // 因为二者为一对一关系，所以需检查二者有没有参与过绑定
//            $is_exist = UserShopModel::where('uid', $uid)->orWhere(function ($query) use ($shop_id) {
//                $query->where('shop_id', $shop_id);
//            })->first();
//        }

        else {
            // 一个店铺可以被多个店铺账号绑定，因此只需检测店铺账号是否被绑定过
            $is_exist = UserShopModel::query()->where('uid', $uid)->first();
        }

        if ($is_exist) {
            return ['code' => ErrorCode::FORBID_BIND];
        }
        $res = true;
        if ($type) {
            UserShopModel::where(['uid' => $uid])->update([
                'shop_id' => $shop_id,
            ]);
        } else {
            $res = UserShopModel::create([
                'uid' => $uid,
                'shop_id' => $shop_id,
            ]);
        }
        if ($res) {
            return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $uid, 'remarks' => 'shop_id:' . $shop_id]];
        }
        return ['code' => ErrorCode::NOT_IN_FORCE];
    }

    public function updateRedisAdminUser()
    {
        $res = $this->getList([], 999);
        foreach ($list = array_column($res['data']->items(), null, 'username') as $k => $v) {
            $list[$k] = json_encode($v);
        }
        $this->redis->del('admin:user');
        $this->redis->hMSet('admin:user', $list);
    }

    /**
     * @param string $phone
     * @param string $password
     *
     * @return array
     * @throws InvalidArgumentException
     */
    public function getAppLogin(string $phone,string $password){
        //验证用户账户密码
        $where[] = ['phone','=',$phone];
        $where[] = ['role','=',3];
        $user = UserModel::query()->where($where)->first();
        if($user) {
            if(password_verify(trim($password),$user->password)){
                $shop_id = UserShopModel::query()->where(['uid' => $user['id']])->value('shop_id');
                $userData = [
                    'uid' => $user->id,
                    'shop_id' => $shop_id,
                    'phone' => $user->phone,
                ];
                $token = $this->jwt->setScene('shopApp')->getToken($userData);
                $data = [
                    'token' => (string)$token,
                    'exp' => $this->jwt->setScene('shopApp')->getTTL(),
                ];
                return ['code' => ErrorCode::SUCCESS,'data' => $data];
            }else{
                return ['code' => ErrorCode::AUTH_ERROR];
            }
        }else{
            return ['code' => ErrorCode::AUTH_ERROR];
        }
    }
    /**
     * 根据手机号查详细信息
     * @param array $where
     * @param string $phone
     * @param array $field
     * @return array|\Hyperf\Database\Model\Builder|\Hyperf\Database\Model\Model|object
     */
    public function getUserInfo(string $phone)
    {
        $where[]= ['phone','=',$phone];
        return UserModel::query()
            ->where($where)
            ->first();
    }

    /**
     * 登录成功列表信息
     * @param array $where
     * @param array $field
     * @return array|\Hyperf\Database\Model\Builder|\Hyperf\Database\Model\Model|object
     */
    public function getUserManul(array $where,$field = [])
    {
        return UserModel::query()
            ->where($where)
            ->where('role','=',3)
            ->join('hf_admin_user_shop as us','us.uid','=','admin_users.id')
            ->select($field)
            ->first();
    }

    /**
     * 修改密码
     * @param string $phone
     * @param array $updateData
     * @return array|bool|\Hyperf\Database\Model\Builder|\Hyperf\Database\Model\Model|object
     */
    public function updatePassword(string $phone,array $updateData)
    {
        return UserModel::query()
            ->where('phone','=',$phone)
            ->update($updateData);
    }


    /**
     * 修改密码
     * @param $params
     * @return array
     */
    public function editPassword($params)
    {
        $user = UserModel::query()->find($params['id']);
        if (!$user) {
            return ['code' => ErrorCode::NOT_EXIST];
        }
        if(strlen(trim($params['new_password'])) < 6){
            return ['code' => ErrorCode::PASSWORD_LENGTH_SIX];
        }
        if (!password_verify(trim($params['old_password']), $user -> password)) {
            return ['code' => ErrorCode::ORIGINAL_PASSWORD_ERROR];
        }
//        if($user -> password == password_hash($params['new_password'], PASSWORD_DEFAULT)){
//            return ['code' => ErrorCode::ERROR_BY_PASSWORD];
//        }

        $attributes = [
            'password' => array_key_exists('new_password', $params) ? password_hash($params['new_password'], PASSWORD_DEFAULT) : $user->password,
        ];

        $res = $user->update($attributes);
        if(!$res){
            return ['code' => ErrorCode::NOT_IN_FORCE];
        }

        return ['code' => ErrorCode::SUCCESS, 'data' => [], 'info' => ['target_id' => $params['id']]];
    }
}
